﻿/*
 *    Copyright © 2012 FPInst authors
 *
 *      This file is part of the FPInst project 
 *      (for more information, see: http://code.google.com/p/fpinst/).
 *
 *    FPInst is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    FPInst is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with FPInst.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Runtime.Remoting.Metadata.W3cXsd2001;

namespace Cellum.Tools
{
    public class Utils
    {
        /// <summary>
        /// Hex Dump a byte array.
        /// </summary>
        /// <param name="b">ource array</param>
        /// <param name="startoff">source offset</param>
        /// <param name="length">number of bytes to dump</param>
        /// <returns>hexa string representing the array</returns>
        public static string Hexa(byte[] b, int startoff, int length)
        {
            byte[] temp = new byte[length];
            Array.Copy(b, startoff, temp, 0, length);
            return Hexa(temp);
        }

        public static string Hexa(byte[] data)
        {
            return new SoapHexBinary(data).ToString();
        }

        public static byte[] Adec(string s)
        {
            return SoapHexBinary.Parse(s).Value;
        }

        public static byte Adec2(string s)
        {
            return byte.Parse(s, NumberStyles.HexNumber);
        }

        public static short Adec4(string s)
        {
            return short.Parse(s, NumberStyles.HexNumber);
        }

        public static int Adec8(string s)
        {
            return int.Parse(s, NumberStyles.HexNumber);
        }

        public static long Adec16(string s)
        {
            return long.Parse(s, NumberStyles.HexNumber);
        }

        public static string Hex2(byte b)
        {
            string s = "";

            s = String.Format("{0:X}", b).PadLeft(2, '0');

            return s;
        }

        public static string Hex4(Int16 b)
        {
            string s = "";

            s = String.Format("{0:X}", b).PadLeft(4, '0');

            return s;
        }

        public static string Hex8(Int32 b)
        {
            string s = "";

            s = String.Format("{0:X}", b).PadLeft(8, '0');

            return s;
        }

        public static string Hex10(Int64 b)
        {
            string s = "";

            s = String.Format("{0:X}", b).PadLeft(10, '0');

            return s;
        }

        public static string Hex16(Int64 b)
        {
            string s = "";

            s = String.Format("{0:X}", b).PadLeft(16, '0');

            return s;
        }
    }

    public static class GraphicsExtensions
    {
        public static void DrawCircle(this Graphics g, Pen pen, int x, int y, int r)
        {
            g.DrawEllipse(pen, x - r / 2, y - r / 2, r, r);
        }
        public static void DrawCircle(this Graphics g, Pen pen, Single x, Single y, int r)
        {
            g.DrawEllipse(pen, x - r / 2, y - r / 2, r, r);
        }

        public static void FillCircle(this Graphics g, Brush b, Single x, Single y, int r)
        {
            g.FillEllipse(b, x - r / 2, y - r / 2, r, r);
        }
        public static void FillCircle(this Graphics g, Brush b, int x, int y, int r)
        {
            g.FillEllipse(b, x - r / 2, y - r / 2, r, r);
        }

    }

    public class GraphicsHelper
    {

        public static PointF GetCirclePoint(int x, int y, int r, double deg)
        {
            double rad = ToRad(deg);
            double px = Math.Sin(rad) * r + x;
            double py = (-1 * Math.Cos(rad)) * r + y;
            PointF pret = new PointF((float)px, (float)py);
            return pret;
        }

        public static PointF[] CalculateHandleCenters(int x, int y, int r, int petals, float startdeg)
        {
            PointF[] pret = new PointF[petals];
            double rotrad = ToRad(startdeg);
            double incangle = ((2 * Math.PI) / petals);

            for (int i = 0; i < petals; i++)
            {
                double deg = (incangle * i) + rotrad;
                double px = Math.Sin(deg) * r + x;
                double py = (-1 * Math.Cos(deg)) * r + y;
                pret[i] = new PointF((float)px, (float)py);
            }
            return pret;
        }

        public static GraphicsPath GetHandle(int x, int y, int r, int petals, float startdeg, float gripsize, float thickness)
        {
            float sweepangle = 160;
            double incdeg =  ToDeg(((2 * Math.PI) / petals));
            double gripdeg = ToDeg(gripsize) + 2;   // corrected by +2 to not to touch the grip
            float gripr = gripsize * r;
            float innerr = r - thickness;

            PointF[] pfs = CalculateHandleCenters(x, y, r, petals, startdeg);
            GraphicsPath gp = new GraphicsPath();
            gp.StartFigure();
            for (int i = 0; i < petals; i++)
            {
                double centerangle = (incdeg * i) + startdeg; 
                double startangle =  centerangle + 90 + (sweepangle / 2);
                gp.AddArc((float)(pfs[i].X - gripr / 2), (float)(pfs[i].Y - gripr / 2), 
                    gripr, gripr, (float)startangle, (-1 * sweepangle));
                gp.AddArc(x - r, y - r, 2*r, 2*r, (float)(centerangle + 270 + (gripdeg / 2)), (float)(incdeg - gripdeg));
            }

            gp.CloseFigure();
            gp.AddEllipse(x - innerr, y - innerr, 2 * innerr, 2 * innerr);

            return gp;            
        }

        public static PointF[] GetMarker(int x, int y, int r, float startdeg, float len, float mthicknessdeg)
        {
            PointF[] rect = new PointF[4];

            double startrad = ToRad(startdeg);
            double mthickpix = Math.Sin(ToRad(mthicknessdeg));
            rect[0] = GetCirclePoint(x, y, r, startdeg - (mthicknessdeg / 2));
            rect[1] = GetCirclePoint(x, y, r, startdeg + (mthicknessdeg / 2));
            rect[2].X = (float)(rect[1].X - (len * Math.Sin(startrad)));
            rect[2].Y = (float)(rect[1].Y - (-1 * len * Math.Cos(startrad)));
            rect[3].X = (float)(rect[0].X - (len * Math.Sin(startrad)));
            rect[3].Y = (float)(rect[0].Y - (-1 * len * Math.Cos(startrad)));

            return rect;
        }

        public static double ToRad(double deg)
        {
            return ((2 * Math.PI) / 360) * deg;
        }

        public static double ToDeg(double rad)
        {
            return (rad / (2 * Math.PI)) * 360;
        }

        
    }
}
